package com.doit.day06

object _11_上下文限定 {
  def main(args: Array[String]): Unit = {
    /**
     * 泛型的上下文界定
     */

    case class Dog(age:Int,weight:Int)
    case class Cat(age:Int,weight:Int)

    //我想比较两个老虎的大小  单纯的老虎，没有实现compare方法的话，是没有办法调用compare来比较的
    //两个办法，第一个办法，在类上实现Ordered 特质，重写 compareTo方法
    //第二个方法，传一个比较器进去，这样他们就可以用比较器来比较了
    def bigger(tiger: Dog,tiger1:Dog,cmp:Ordering[Dog]):Dog={
      if (cmp.compare(tiger,tiger1)> 0) tiger else tiger1
    }

    val order: Ordering[Dog] = new Ordering[Dog] {
      override def compare(x: Dog, y: Dog) = x.age.compare(y.age)
    }

    val dog: Dog = bigger(Dog(1, 11), Dog(2, 12), order)
    println(dog)

    //上面这种方法确实是可以比较，但是只能比较老虎，我想比较个猫好像就比较不了了
    //想比较猫，得重新在写一个
    def bigger1(cat: Cat,cat1:Cat,cmp:Ordering[Cat]):Cat={
      if (cmp.compare(cat,cat1)> 0) cat else cat1
    }

    //不过回头想比较狗狗，又要写一个，比较麻烦，不通用
    //这时候就可以定义泛型了
    def bigger2[T](t: T,t1:T,cmp:Ordering[T]):T={
      if (cmp.compare(t,t1)> 0) t else t1
    }

    //方法的调用  这样是没什么问题的
    //但是在马大爷眼里，这么写代码，多low啊，不符合马大爷的气质，他就开始搞事情了
    bigger2[Cat](Cat(10,100),Cat(20,80),new Ordering[Cat] {
      override def compare(x: Cat, y: Cat) = x.age - y.age
    })

    //咱们不是有隐式转换嘛，能不能把这个比较器呢？
    //我上下文中找找，有没有什么隐式的比较器可以拿过来用，如果有我就直接拿过来，这样就不用传比较器了，去偷一个不香嘛
    //bigger3[T :Ordering]  注意：如果想让他自己偷一个，那么需要实现上下文界定，不然是没办法使用的
 /*   def bigger3[T : Eat](t: T,t1:T):T={
      if(implicitly[Eat].eat()>0) t else t1
    }

    /**
     * 两种创建隐式比较器对象的写法
     */
    //    implicit val value: Ordering[Cat] = new Ordering[Cat] {
    //      override def compare(x: Cat, y: Cat) = x.age - y.age
    //    }

//    implicit val value1 = Ordering.by[Cat,Int](cat=>cat.age)
   implicit val ssaaa = new Ordering[Cat] {
      override def compare(x: Cat, y: Cat) = x.age.compare(y.age)
    }

    bigger3[Cat](Cat(10,100),Cat(20,80))*/


    def bigger5[T](a:T,b:T)(implicit e:Eat): T ={
      if(e.eat()>0) a else b
    }

    implicit val aaaaaa = new Eat {
      override def eat() = 1
    }

    bigger5[Cat](Cat(1,2),Cat(2,3))


  }

}


trait Eat{
  def eat():Int
}